import { defineComponent } from 'vue-demi'
import { VALUE_NAME } from '../../utils/constant'
import { h } from '../../utils/domutil'
import { getNextId } from '../../utils/numutils'
import gsap from 'gsap'

const NAME = 'yc-screen-line'

export default defineComponent({
  name: NAME,
  props: {
    [VALUE_NAME]: {
      type: String,
      default: '0,0 h100'
    },
    /** 是否激活 */
    active: {
      type: Boolean,
      default: false
    },
    /** 线条所在层级 */
    level: {
      type: String,
      default: 'bottom' // bottom middle top
    },
    /** 里面的线宽 */
    innerLineWidth: {
      type: Number,
      default: 4
    },
    /** 外面的线宽 */
    outerLineWidth: {
      type: Number,
      default: 16
    },
    /** 里面的线未激活时的颜色 */
    innerLineColor: {
      type: String,
      default: '#6e6e6e'
    },
    /** 里面的线激活时的颜色 */
    innerLineActiveColor: {
      type: String,
      default: '#ffffff'
    },
    /** 外面的线起始渐变色 */
    outerLineStartColor: {
      type: String,
      default: 'red'
    },
    /** 外面的线结束渐变色 */
    outerLineEndColor: {
      type: String,
      default: 'blue'
    },
    /** 拐弯处的圆角大小 */
    borderRadius: {
      type: Number,
      default: 20
    },
    /** 动画时长（秒） */
    duration: {
      type: Number,
      default: 1
    }
  },
  data() {
    return {
      id: getNextId(),
      /** 虚实线长度 */
      strokeDashArray: 0,
      /** 虚实线偏移量 */
      strokeDashOffset: 0,
      /** 动画 */
      activeTween: undefined,
      /** 矩形裁剪区域 */
      clipRect: {
        x: 0,
        y: 0,
        width: 0,
        height: 0
      }
    }
  },
  computed: {
    /** 线条数据分段。第一段是起始点，后面是线段 */
    segments() {
      return this[VALUE_NAME].split(/\s+/)
    },
    /** 起点位置 */
    startPoint() {
      const pointArr = this.segments[0].split(',')
      const x = Number(pointArr[0])
      const y = Number(pointArr[1])
      return { x, y }
    },
    /** 终点位置 */
    endPoint() {
      const point = {
        ...this.startPoint
      }
      this.segments.slice(1).forEach((str) => {
        const dir = str.charAt(0) // 方向
        let num = Number(str.substring(1)) // 长度（含方向）
        if (dir === 'h') {
          // 如果水平
          point.x += num
        } else {
          // 如果垂直
          point.y += num
        }
      })
      return point
    },
    /** 渐变方向控制点信息 */
    linearGradientPointInfo() {
      const rect = {
        top: Math.min(this.startPoint.y, this.endPoint.y),
        bottom: Math.max(this.startPoint.y, this.endPoint.y),
        left: Math.min(this.startPoint.x, this.endPoint.x),
        right: Math.max(this.startPoint.x, this.endPoint.x)
      }

      const arr1 = [this.startPoint.x, this.endPoint.x, this.startPoint.y, this.endPoint.y]
      const arr2 = arr1.reduce((arr, item, index) => {
        if (index < 2) {
          // 前两个为x
          if (item === rect.left) {
            arr.push('0')
          } else {
            arr.push('1')
          }
        } else {
          // 后两个点为y
          if (item === rect.top) {
            arr.push('0')
          } else {
            arr.push('1')
          }
        }
        return arr
      }, [])
      return { x1: arr2[0], x2: arr2[1], y1: arr2[2], y2: arr2[3] }
    },
    /** 绘制线段的路径 */
    path() {
      return this.segments.reduce((p, str, index) => {
        if (index === 0) {
          // 如果是起点
          p += str
        } else {
          // 如果是连线
          if (this.borderRadius <= 0 || this.segments.length === 2) {
            // 如果拐弯不是圆角 或者 只有一段
            p += ` ${str}`
          } else {
            // 其他情况需要减去圆角
            const dir = str.charAt(0)
            let num = Number(str.substring(1))
            const offset = (num / Math.abs(num)) * this.borderRadius
            if (index === 1) {
              // 如果是第一段，减去后面的圆角长度
              num -= offset
              p += ` ${dir}${num}`
              p += getQPath(this.segments, index, dir, offset, this.borderRadius)
            } else if (index === this.segments.length - 1) {
              // 如果是最后一段，减去前面的圆角长度
              num -= offset
              p += ` ${dir}${num}`
            } else {
              // 如果是中间线段，减去前后的圆角长度
              num -= offset * 2
              p += ` ${dir}${num}`
              p += getQPath(this.segments, index, dir, offset, this.borderRadius)
            }
          }
        }
        return p
      }, 'M')
    },
    /** 绘制矩形的参数 */
    rect() {
      if (this.segments.length === 2) {
        // 一条直线，计算矩形的x、y、width、height
        const halfWidth = this.outerLineWidth / 2
        const str = this.segments[1]
        const dir = str.charAt(0) // 方向
        let num = Number(str.substring(1)) // 长度（含方向）
        let x, y, width, height
        if (dir === 'h') {
          // 如果是水平
          y = this.startPoint.y - halfWidth
          width = Math.abs(num)
          height = this.outerLineWidth
          if (num >= 0) {
            // 如果是向右
            x = this.startPoint.x
          } else {
            // 如果是向左
            x = this.startPoint.x + num
          }
        } else {
          // 如果是垂直
          x = this.startPoint.x - halfWidth
          width = this.outerLineWidth
          height = Math.abs(num)
          if (num >= 0) {
            // 如果是向下
            y = this.startPoint.y
          } else {
            // 如果是向上
            y = this.startPoint.y + num
          }
        }
        return { x, y, width, height }
      } else {
        return { x: 0, y: 0, width: 0, height: 0 }
      }
    },
    /** 第一段线的朝向。上top下bottom左left右right */
    direction() {
      const str = this.segments[1]
      const dir = str.charAt(0) // 方向
      let num = Number(str.substring(1)) // 长度（含方向）
      if (dir === 'h') {
        // 水平
        if (num >= 0) {
          return 'right'
        } else {
          return 'left'
        }
      } else {
        // 垂直
        if (num >= 0) {
          return 'bottom'
        } else {
          return 'top'
        }
      }
    }
  },
  watch: {
    active() {
      this.tryRunAnimation()
    }
  },
  mounted() {
    this.initOuterLine()
    this.tryRunAnimation()
    // 测试动画
    window.setTimeout(() => {
      this.runRestoreAnimation()
    }, 2000)
    window.setTimeout(() => {
      this.tryRunAnimation()
    }, 3000)
  },
  methods: {
    /** 初始化外面的线的相关数据 */
    initOuterLine() {
      if (this.segments.length > 2) {
        // 如果是折线
        this.strokeDashArray = this.$refs.line.getTotalLength()
        this.strokeDashOffset = this.strokeDashArray
      } else {
        // 如果是单一直线
        if (this.direction === 'top') {
          // 如果是向上
          // 起点在最下面
          this.clipRect = {
            ...this.rect,
            y: this.rect.y + this.rect.height,
            height: 0
          }
        } else if (this.direction === 'bottom') {
          // 如果是向下
          // 起点在最上面
          this.clipRect = {
            ...this.rect,
            height: 0
          }
        } else if (this.direction === 'left') {
          // 如果是向左
          // 起点在最右边
          this.clipRect = {
            ...this.rect,
            x: this.rect.x + this.rect.width,
            width: 0
          }
        } else {
          // 如果是向右
          // 起点在最左边
          this.clipRect = {
            ...this.rect,
            width: 0
          }
        }
      }
    },
    /** 执行激活动画 */
    runActiveAnimation() {
      if (this.activeTween) {
        this.activeTween.play()
      } else {
        if (this.segments.length > 2) {
          // 表示非单一直线
          this.activeTween = gsap.to(this, {
            duration: this.duration,
            strokeDashOffset: 0
          })
        } else {
          // 如果是单一直线
          this.activeTween = gsap.to(this.clipRect, {
            duration: this.duration,
            ...this.rect
          })
        }
      }
    },
    /** 执行还原动画 */
    runRestoreAnimation() {
      if (this.activeTween) {
        this.activeTween.reverse()
      }
    },
    /** 尝试执行动画 */
    tryRunAnimation() {
      if (this.active) {
        this.runActiveAnimation()
      } else {
        this.runRestoreAnimation()
      }
    },
    /** 获取底层线条 */
    getBottomLine() {
      return h('path', {
        ref: 'line',
        attrs: {
          d: this.path,
          stroke: this.innerLineColor,
          'stroke-width': this.innerLineWidth,
          fill: 'none'
        }
      })
    },
    /** 获取中层线条 */
    getMiddleLine() {
      return this.segments.length === 2
        ? h('rect', {
            attrs: {
              ...this.rect,
              fill: `url(#${NAME}linearGradient${this.id})`,
              'clip-path': `url(#${NAME}clipPath${this.id})`
            }
          })
        : h('path', {
            ref: 'line',
            attrs: {
              d: this.path,
              stroke: `url(#${NAME}linearGradient${this.id})`,
              'stroke-width': this.outerLineWidth,
              'stroke-dasharray': this.strokeDashArray,
              'stroke-dashoffset': this.strokeDashOffset,
              fill: 'none'
            }
          })
    },
    /** 获取上层线条 */
    getTopLine() {
      return h('path', {
        ref: 'line',
        attrs: {
          d: this.path,
          stroke: this.innerLineActiveColor,
          'stroke-width': this.innerLineWidth,
          'stroke-dasharray': this.strokeDashArray,
          'stroke-dashoffset': this.strokeDashOffset,
          fill: 'none',
          'clip-path': this.segments.length === 2 ? `url(#${NAME}clipPath${this.id})` : undefined
        }
      })
    },
    /** 获取线条 */
    getLine() {
      if (this.level === 'top') {
        return this.getTopLine()
      } else if (this.level === 'middle') {
        return this.getMiddleLine()
      } else {
        return this.getBottomLine()
      }
    }
  },
  render() {
    return h('g', { class: { 'is-active': this.active } }, [
      h('defs', [
        h(
          'linearGradient',
          {
            attrs: {
              id: `${NAME}linearGradient${this.id}`,
              ...this.linearGradientPointInfo
            }
          },
          [
            h('stop', {
              attrs: {
                offset: '0%',
                'stop-color': this.outerLineStartColor
              }
            }),
            h('stop', {
              attrs: {
                offset: '100%',
                'stop-color': this.outerLineEndColor
              }
            })
          ]
        ),
        h('clipPath', { attrs: { id: `${NAME}clipPath${this.id}` } }, [
          h('rect', {
            attrs: {
              ...this.clipRect
            }
          })
        ])
      ]),
      this.getLine()
    ])
  }
})

/** 获取拐弯路径 */
function getQPath(arr, index, dir, offset, borderRadius) {
  // 根据下一段朝向来判断拐弯方向
  const nextStr = arr[index + 1]
  const nextNum = Number(nextStr.substring(1))
  const nextOffset = (nextNum / Math.abs(nextNum)) * borderRadius
  if (dir === 'h') {
    // 当前h水平，则下一个垂直
    return ` q${offset} 0 ${offset} ${nextOffset}`
  } else {
    // 当前v垂直，则下一个水平
    return ` q0 ${offset} ${nextOffset} ${offset}`
  }
}
